Skip to content

fix(deps): migrate to stable pkcs5 / pkcs8 / ed25519 and loosen prerelease pins (extends #697) - #702

Merged
Eugeny merged 4 commits into
Eugeny:mainfrom
simon-escapecode:fix/697-migrate-stable-crypto-stack
May 16, 2026
Merged

fix(deps): migrate to stable pkcs5 / pkcs8 / ed25519 and loosen prerelease pins (extends #697)#702
Eugeny merged 4 commits into
Eugeny:mainfrom
simon-escapecode:fix/697-migrate-stable-crypto-stack

Conversation

@simon-escapecode

Copy link
Copy Markdown
Contributor

Context

After pkcs8 0.11.0 stable landed (2026-04-28, see #697), russh's prerelease crypto stack falls over for any downstream consumer that pulls in rsa = "^0.10.0-rc.18". Issue #697 was closed by 2a49916 with a stopgap that pins every prerelease dep with =, releasing as 0.60.2. That fixes russh in isolation but blocks downstream consumers: their newer rsa pulls in pkcs8 0.11.0 stable through the dep graph, which makes 0.60.2's rsa = "=0.10.0-rc.16" and pkcs8 = "=0.11.0-rc.11" unresolvable in the same workspace.

This PR completes the work of #697 by migrating russh's source to the stable pkcs5 / pkcs8 / ed25519 APIs and loosening the prerelease pins so the resolver can climb to versions that compile against the stable formats family.

Change

Source change in russh/src/keys/format/pkcs8.rs:

- pkcs5::pbes2::Parameters::pbkdf2_sha256_aes256cbc(rounds, &salt, iv)
+ pkcs5::pbes2::Parameters::generate_pbkdf2_sha256_aes256cbc(rounds, &salt, iv)

The pbkdf2_sha256_aes256cbc constructor existed in pkcs5 0.8.0-rc.13 and was renamed to generate_pbkdf2_sha256_aes256cbc in 0.8.0 stable (per the pkcs5 CHANGELOG and current docs.rs). Same arguments, same crypto semantics.

Floor bumps in russh/Cargo.toml:

Crate Before After
crypto-bigint =0.7.0-rc.28 0.7.3
ecdsa =0.17.0-rc.16 0.17.0-rc.18
ed25519-dalek =3.0.0-pre.6 3.0.0-pre.7
elliptic-curve =0.14.0-rc.28 0.14.0-rc.32
p256 / p384 / p521 =0.14.0-rc.7 0.14.0-rc.9
pkcs5 =0.8.0-rc.13 0.8 (stable)
pkcs8 =0.11.0-rc.11 0.11 (stable)
rsa =0.10.0-rc.16 0.10.0-rc.18
spki =0.8.0-rc.4 0.8 (stable)

The = prefix is dropped on every line above. Each new floor is the first version of the crate that compiles against the stable formats family. The cascade is forced because rsa 0.10.0-rc.16 source itself fails against pkcs8 0.11.0 stable with the same KeyMalformed enum-variant signature change that broke ed25519-rc.4 in the #697 report, and primefield 0.14.0-rc.7 (pulled in via p256/p384/p521 0.14.0-rc.7) fails against crypto-bigint 0.7.3 with const-generic type-inference errors.

Other prerelease pins (aead, aes-gcm, curve25519-dalek, ml-kem, the internal-russh-num-bigint fork, pkcs1) are left untouched. Each of those crates' latest published version equals the pinned version today, so loosening would be a no-op for resolution.

Verification

On the fork branch with rustc 1.88.0 (the rust-toolchain.toml floor):

cargo build --workspace                                   clean
cargo build --workspace --all-features                    clean
cargo clippy --workspace -- -D warnings                   clean
cargo clippy --workspace --all-features -- -D warnings    clean
cargo fmt --check                                         clean
cargo test --workspace                                    76 lib tests + all
                                                          submodule and doc-tests
                                                          pass
cargo test --workspace --all-features                     77 lib tests + all
                                                          submodule and doc-tests
                                                          pass

cargo minimal-versions check --all-features --no-dev-deps was not run locally (cargo-minimal-versions and cargo-hack are not installed in the development environment). The new floors are chosen so the lowest version satisfying each loosened spec is the first version that compiles against the stable formats family, which is what minimal-versions selects in the absence of an = pin. CI is the canonical check.

Downstream evidence

The fix unblocks at least one downstream consumer: the rustfs SFTP server. The rustfs feature branch carries:

[patch.crates-io]
russh = { git = "https://github.com/simon-escapecode/russh", branch = "fix/697-migrate-stable-crypto-stack" }

against rustfs's russh = "0.60.0" workspace dep. With this patch in place, rustfs resolves cleanly against rsa 0.10.0-rc.18, pkcs5 0.8.0 stable, pkcs8 0.11.0 stable, ed25519 3.0.0 stable, and the rest of the stable formats family. Without the patch, the rustfs build fails on the same KeyMalformed signature mismatch in rsa 0.10.0-rc.16 source that blocks anyone else trying to consume rsa rc.18+ alongside russh 0.60.2.

Risk

The bumps ed25519-dalek 3.0.0-pre.6 -> 3.0.0-pre.7, ecdsa rc.16 -> rc.18, elliptic-curve rc.28 -> rc.32, and p256 / p384 / p521 rc.7 -> rc.9 are minor RustCrypto patch-level moves. The russh test suite covers the affected key handling and ECDSA / EdDSA paths and passes on the fork at every step. The rsa = "=0.10.0-rc.16" -> "0.10.0-rc.18" move is the deliberate fix for downstream compatibility; the = was the root cause of #697's downstream impact.

If cargo minimal-versions check --all-features --no-dev-deps flags any further floor that the in-tree CI catches, the fix shape is the same: bump the floor to the first version that compiles against the stable formats family. Happy to amend.

…lease pins

Renames the rc.13 pkcs5 call site to its 0.8.0 stable name and drops the
`=` constraints introduced by 2a49916 (Eugeny#697) on the RustCrypto prerelease
stack. Downstream consumers that bring in newer rsa rc.X (or 0.10.0
stable, when it lands) can now resolve russh cleanly without a
[patch.crates-io] override.

Source change in russh/src/keys/format/pkcs8.rs:

    pkcs5::pbes2::Parameters::pbkdf2_sha256_aes256cbc(rounds, &salt, iv)

becomes

    pkcs5::pbes2::Parameters::generate_pbkdf2_sha256_aes256cbc(rounds, &salt, iv)

Floor bumps in russh/Cargo.toml:

    crypto-bigint        0.7.0-rc.28  ->  0.7.3
    ecdsa                0.17.0-rc.16 ->  0.17.0-rc.18
    ed25519-dalek        3.0.0-pre.6  ->  3.0.0-pre.7
    elliptic-curve       0.14.0-rc.28 ->  0.14.0-rc.32
    p256 / p384 / p521   0.14.0-rc.7  ->  0.14.0-rc.9
    pkcs5                0.8.0-rc.13  ->  0.8 (stable)
    pkcs8                0.11.0-rc.11 ->  0.11 (stable)
    rsa                  0.10.0-rc.16 ->  0.10.0-rc.18
    spki                 0.8.0-rc.4   ->  0.8 (stable)

The `=` prefix is dropped on every line above. Each floor is the first
version of the crate that compiles against the stable formats family.
The cascade is forced by rsa 0.10.0-rc.16 source failing against
pkcs8 0.11.0 stable (same `KeyMalformed` enum-variant rename that broke
ed25519-rc.4 in the Eugeny#697 report) and primefield 0.14.0-rc.7 failing
against crypto-bigint 0.7.3.

Other prerelease pins (aead, aes-gcm, curve25519-dalek, ml-kem,
num-bigint fork, pkcs1) are left untouched. Each one's latest published
version matches the pinned version today, so loosening would be a no-op
for resolution.

Gates run on this branch with rustc 1.88.0 (the rust-toolchain.toml
floor):

    cargo build --workspace                                   clean
    cargo build --workspace --all-features                    clean
    cargo clippy --workspace -- -D warnings                   clean
    cargo clippy --workspace --all-features -- -D warnings    clean
    cargo fmt --check                                         clean
    cargo test --workspace                                    76 lib tests +
                                                              all submodule
                                                              and doc-tests
                                                              pass
    cargo test --workspace --all-features                     77 lib tests +
                                                              all submodule
                                                              and doc-tests
                                                              pass
simon-escapecode added a commit to simon-escapecode/rustfs that referenced this pull request May 8, 2026
Added full SFTPv3 functionality. Added SFTP subsystem to the protocols crate, gated behind the new sftp cargo feature. The driver translates each SFTPv3 packet into an S3 call against the existing StorageBackend, so SFTP shares the same bucket layout, IAM, and lifecycle rules as the existing FTPS, WebDAV, and Swift drivers. SSH username maps to the IAM access key and SSH password to the secret key.

Added russh 0.60 and russh-sftp 2.1 as workspace dependencies. A temporary [patch.crates-io] entry pins russh to a fork branch carrying the upstream fix at Eugeny/russh#702. The patch resolves an rsa 0.10.0-rc.18 vs pkcs5 prerelease conflict that no released russh version handles. It is removed once the russh PR merges and a release ships.

Added 33 SFTPv3 compliance test cases (test_sftp_compliance_suite shared-session, test_sftp_compliance_readonly, test_sftp_compliance_standalone one-spawn-per-case) plus four regression-prevention layers guarding against silent feature deletion: compile-time module assertion, module-presence unit test, cross-module Protocol enum assertion, and end-to-end SSH banner test against the running binary.

Refs rustfs#2478.
simon-escapecode added a commit to simon-escapecode/rustfs that referenced this pull request May 8, 2026
Added full SFTPv3 functionality. Added SFTP subsystem to the protocols crate, gated behind the new sftp cargo feature. The driver translates each SFTPv3 packet into an S3 call against the existing StorageBackend, so SFTP shares the same bucket layout, IAM, and lifecycle rules as the existing FTPS, WebDAV, and Swift drivers. SSH username maps to the IAM access key and SSH password to the secret key.

Added russh 0.60 and russh-sftp 2.1 as workspace dependencies. A temporary [patch.crates-io] entry pins russh to a fork branch carrying the upstream fix at Eugeny/russh#702. The patch resolves an rsa 0.10.0-rc.18 vs pkcs5 prerelease conflict that no released russh version handles. It is removed once the russh PR merges and a release ships.

Added 33 SFTPv3 compliance test cases (test_sftp_compliance_suite shared-session, test_sftp_compliance_readonly, test_sftp_compliance_standalone one-spawn-per-case) plus four regression-prevention layers guarding against silent feature deletion: compile-time module assertion, module-presence unit test, cross-module Protocol enum assertion, and end-to-end SSH banner test against the running binary.

Refs rustfs#2478.
@houseme

houseme commented May 15, 2026

Copy link
Copy Markdown

#635

Comment thread russh/Cargo.toml Outdated
@Eugeny

Eugeny commented May 16, 2026

Copy link
Copy Markdown
Owner

Pinned the prerelease deps (see the comment) and bumped ml-kem too since 0.3 is stable now - I'm interested in adoption from rustfs so feel free to report anything you run into!

@Eugeny
Eugeny merged commit 63674d9 into Eugeny:main May 16, 2026
@houseme

houseme commented May 17, 2026

Copy link
Copy Markdown

Thank you, looking forward to more cooperation between us in the future, and mutual growth.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants